package cn.sxgan.core.services.impl;

import cn.sxgan.common.consts.CommonConst;
import cn.sxgan.common.consts.RedisConst;
import cn.sxgan.common.entity.SysMenu;
import cn.sxgan.common.entity.SysRole;
import cn.sxgan.common.entity.SysUser;
import cn.sxgan.common.entity.converts.ISysMenuConvert;
import cn.sxgan.common.entity.converts.ISysRoleConvert;
import cn.sxgan.common.entity.converts.ISysUserConvert;
import cn.sxgan.common.entity.query.SysRoleQuery;
import cn.sxgan.common.entity.query.SysUserQuery;
import cn.sxgan.common.entity.sys.GlobalUser;
import cn.sxgan.common.entity.sys.PageRequest;
import cn.sxgan.common.entity.sys.RequestHolder;
import cn.sxgan.common.entity.vo.SysMenuVO;
import cn.sxgan.common.entity.vo.SysRoleAndMenuVO;
import cn.sxgan.common.entity.vo.SysRoleVO;
import cn.sxgan.common.entity.vo.SysUserAndRoleVO;
import cn.sxgan.common.entity.vo.SysUserVO;
import cn.sxgan.common.enums.KeyPrefixEnum;
import cn.sxgan.common.enums.ResStatusEnum;
import cn.sxgan.common.exception.ApiException;
import cn.sxgan.common.redis.RedisUtil;
import cn.sxgan.common.response.Result;
import cn.sxgan.common.utils.CommonUtils;
import cn.sxgan.common.utils.JwtUtils;
import cn.sxgan.core.services.ISysUserService;
import cn.sxgan.db.mappers.ISysMenuMapper;
import cn.sxgan.db.mappers.ISysRoleMapper;
import cn.sxgan.db.mappers.SysUserMapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Description: 用户查询服务
 * @Author: sxgan
 * @Date: 24/7/12 17:39
 * @Version: 1.0
 **/
@Slf4j
@Service
public class UserServiceImpl implements ISysUserService {
    
    @Resource
    SysUserMapper userMapper;
    
    @Resource
    ISysRoleMapper roleMapper;
    
    @Resource
    RedisUtil redisUtil;
    @Autowired
    private ISysMenuMapper iSysMenuMapper;
    
    @Override
    public SysUserVO selectSysUserInfo(GlobalUser currentUser) {
        SysUserVO sysUserVO = new SysUserVO();
        if (currentUser == null || StringUtils.isBlank(currentUser.getEmail())) {
            return sysUserVO;
        }
        SysUserQuery sysUserQuery = new SysUserQuery();
        sysUserQuery.setEmail(currentUser.getEmail());
        List<SysUser> sysUsers = userMapper.selectUserByCondition(sysUserQuery);
        if (!sysUsers.isEmpty()) {
            sysUserVO = ISysUserConvert.INSTANCE.sysUserToVO(sysUsers.getFirst());
        } else {
            return null;
        }
        return sysUserVO;
    }
    
    @Override
    public Result<String> updateSysUserInfo(SysUserVO sysUserVO) {
        GlobalUser globalUser = RequestHolder.getCurrentUser();
        if (sysUserVO == null || StringUtils.isBlank(sysUserVO.getEmail())) {
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_900.getMsg());
        }
        if (!globalUser.getEmail().equals(sysUserVO.getEmail())) {
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_903.getMsg());
        }
        SysUser sysUser = ISysUserConvert.INSTANCE.sysUserVOToDAO(sysUserVO);
        int bool = userMapper.update(sysUser,
                new UpdateWrapper<SysUser>()
                        .eq("email", sysUser.getEmail())
                        .set("user_name", sysUser.getUserName())
                        .set("personal_sign", sysUser.getPersonalSign()));
        if (bool > 0) {
            // 移除redis用户信息
            redisUtil.del(RedisConst.LOGIN_TOKEN_PREFIX + globalUser.getToken());
            // 写入用户信息
            SysUserQuery userQuery = new SysUserQuery();
            userQuery.setEmail(globalUser.getEmail());
            List<SysUser> userList = userMapper.selectUserByCondition(userQuery);
            if (!userList.isEmpty()) {
                SysUser user = userList.get(0);
                HashMap<String, Object> tokenMap = new HashMap<>();
                tokenMap.put("email", user.getEmail());
                tokenMap.put("id", user.getUserId());
                String token = JwtUtils.createToken(tokenMap);
                globalUser.setId(user.getUserId());
                globalUser.setUserName(user.getUserName());
                globalUser.setToken(token);
                redisUtil.set(RedisConst.LOGIN_TOKEN_PREFIX + token, globalUser, CommonConst.LOGIN_TIME_1,
                        TimeUnit.DAYS);
                return Result.success(token, 1, ResStatusEnum.UPDATE_STATUS_200.getMsg());
            }
        }
        return Result.fail(ResStatusEnum.UPDATE_STATUS_500.getMsg());
    }
    
    @Override
    public Result<String> removeUser(Long userId) {
        GlobalUser globalUser = RequestHolder.getCurrentUser();
        if (userId == null || userId <= 0) {
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_900.getMsg());
        }
        SysUserQuery sysUserQuery = new SysUserQuery();
        sysUserQuery.setUserId(userId);
        SysUser sysUser;
        List<SysUser> sysUsers = userMapper.selectUserByCondition(sysUserQuery);
        if (!sysUsers.isEmpty()) {
            sysUser = sysUsers.getFirst();
            if (globalUser.getEmail().equals(sysUser.getEmail())) {
                throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_932.getMsg());
            }
            if (globalUser.getUserType() != 0) {
                throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_911.getMsg());
            }
            sysUser.setDelFlag(1);
            sysUser.setUpdateBy(globalUser.getEmail());
            int update = userMapper.updateById(sysUser);
            if (update > 0) {
                return Result.success(ResStatusEnum.DELETE_STATUS_200.getMsg());
            }
        } else {
            return Result.fail(ResStatusEnum.EXCEPTION_STATUS_912.getMsg());
        }
        return Result.fail(ResStatusEnum.DELETE_STATUS_500.getMsg());
    }
    
    @Override
    @Transactional
    public Result<String> editRole(SysRoleVO sysRoleVO) {
        if (sysRoleVO == null || sysRoleVO.getRoleId() == null) {
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_900.getMsg());
        }
        try {
            SysRole oldSysRole = roleMapper.selectById(sysRoleVO.getRoleId());
            if (oldSysRole == null) {
                return Result.fail(ResStatusEnum.EXCEPTION_STATUS_724.getMsg());
            }
            SysRole sysRole = ISysRoleConvert.INSTANCE.convert(sysRoleVO);
            int update = roleMapper.updateById(sysRole);
            if (update > 0) {
                return Result.success(ResStatusEnum.UPDATE_STATUS_200.getMsg());
            }
            return Result.fail(ResStatusEnum.UPDATE_STATUS_500.getMsg());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("异常", e);
            throw new ApiException(e.getMessage());
        }
    }
    
    @Override
    public Result<String> removeRole(List<Long> roleIds) {
        if (roleIds == null || roleIds.size() <= 0) {
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_900.getMsg());
        }
        try {
            int i = roleMapper.deleteBatchIds(roleIds);
            if (i > 0) {
                return Result.success(ResStatusEnum.DELETE_STATUS_200.getMsg());
            }
            return Result.fail(ResStatusEnum.DELETE_STATUS_500.getMsg());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("异常", e);
            throw new ApiException(e.getMessage());
        }
    }
    
    @Override
    public Result<List<SysUserVO>> findUserList(SysUserQuery req) {
        GlobalUser currentUser = RequestHolder.getCurrentUser();
        SysUserVO sysUserInfo = this.selectSysUserInfo(currentUser);
        Integer userType = sysUserInfo.getUserType();
        if (userType == null || userType != 0) {
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_901.getMsg());
        }
        try {
            CommonUtils.initPageParam(req);
            Page<SysUser> page = PageHelper.startPage(req.getPage(), req.getSize());
            userMapper.selectUserByCondition(req);
            List<SysUserVO> sysUserVOS = ISysUserConvert.INSTANCE.sysUserListToVOList(page.getResult());
            return Result.success(sysUserVOS, page.getTotal());
        } catch (Exception e) {
            e.printStackTrace();
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_999.getMsg());
        }
    }
    
    public Result<List<SysUserAndRoleVO>> findUserRoleList(SysUserQuery sysUserQuery) {
        GlobalUser currentUser = RequestHolder.getCurrentUser();
        SysUserVO sysUserInfo = this.selectSysUserInfo(currentUser);
        Integer userType = sysUserInfo.getUserType();
        if (userType == null || userType != 0) {
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_901.getMsg());
        }
        try {
            CommonUtils.initPageParam(sysUserQuery);
            Page<SysUserAndRoleVO> page = PageHelper.startPage(sysUserQuery.getPage(), sysUserQuery.getSize());
            userMapper.selectUserAndRole(sysUserQuery);
            return Result.success(page.getResult(), page.getTotal());
        } catch (Exception e) {
            e.printStackTrace();
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_999.getMsg());
        }
    }
    
    public Result<List<SysRoleAndMenuVO>> findRoleMenuList(PageRequest pageRequest) {
        GlobalUser currentUser = RequestHolder.getCurrentUser();
        SysUserVO sysUserInfo = this.selectSysUserInfo(currentUser);
        Integer userType = sysUserInfo.getUserType();
        if (userType == null || userType != 0) {
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_902.getMsg());
        }
        try {
            CommonUtils.initPageParam(pageRequest);
            Page<SysRoleAndMenuVO> page = PageHelper.startPage(pageRequest.getPage(), pageRequest.getSize());
            roleMapper.getSysRoleAndMenu();
            return Result.success(page.getResult(), page.getTotal());
        } catch (Exception e) {
            e.printStackTrace();
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_999.getMsg());
        }
    }
    
    public Result<List<SysRoleVO>> findRoleList(PageRequest pageRequest) {
        try {
            List<SysRole> sysRoles = roleMapper.selectSysRoleByCondition(new SysRoleQuery());
            List<SysRoleVO> sysRoleVOS = ISysRoleConvert.INSTANCE.convertList(sysRoles);
            return Result.success(sysRoleVOS);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("异常", e);
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_720.getMsg());
        }
    }
    
    @Override
    @Transactional
    public Result<String> addRole(SysRoleVO sysRoleVO) {
        GlobalUser currentUser = RequestHolder.getCurrentUser();
        if (StringUtils.isBlank(sysRoleVO.getRoleName()) || StringUtils.isBlank(sysRoleVO.getRoleKey())) {
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_900.getMsg());
        }
        try {
            // 添加角色
            SysRole sysRole = ISysRoleConvert.INSTANCE.convert(sysRoleVO);
            String roleId = redisUtil.nextId(KeyPrefixEnum.ROLE_ID, 10, 1, true);
            assert roleId != null;
            sysRole.setRoleId(Long.parseLong(roleId));
            sysRole.setCreateBy(currentUser.getEmail());
            roleMapper.insert(sysRole);
            return Result.success(ResStatusEnum.ADD_STATUS_200.getMsg());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("异常", e);
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_721);
        }
    }
    
    @Override
    public Result<String> bindUserAndRole(Long userId, Long roleId) {
        if (userId == null || roleId == null) {
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_900);
        }
        try {
            // 查询用户
            SysUserQuery sysUserQuery = new SysUserQuery();
            sysUserQuery.setUserId(userId);
            List<SysUser> sysUsers = userMapper.selectUserByCondition(sysUserQuery);
            if (sysUsers.isEmpty()) {
                throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_723);
            }
            SysRoleQuery sysRoleQuery = new SysRoleQuery();
            sysRoleQuery.setRoleId(roleId);
            List<SysRole> sysRoles = roleMapper.selectSysRoleByCondition(sysRoleQuery);
            if (sysRoles.isEmpty()) {
                throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_724.getMsg());
            }
            // 用户角色绑定
            int count = userMapper.bindUserAndRole(userId, roleId);
            if (count > 0) {
                return Result.success();
            } else {
                return Result.fail(ResStatusEnum.EXCEPTION_STATUS_724.getMsg());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("异常", e);
            throw new ApiException(ResStatusEnum.EXCEPTION_STATUS_722.getMsg());
        }
    }
    
    @Override
    public Result<List> findUserMenus() {
        GlobalUser currentUser = RequestHolder.getCurrentUser();
        try {
            // 查询用户角色信息
            SysUserQuery sysUserQuery = new SysUserQuery();
            sysUserQuery.setUserId(currentUser.getId());
            List<SysUserAndRoleVO> sysUserAndRoleVOS = userMapper.selectUserAndRole(sysUserQuery);
            SysUserAndRoleVO sysUserAndRoleVO = sysUserAndRoleVOS.getFirst();
            List<SysRole> sysRoles = sysUserAndRoleVO.getSysRoles();
            List<SysMenu> menus;
            if (sysRoles.isEmpty()) {
                // 默认菜单
                menus = iSysMenuMapper.selectSysMenuByRoleId(CommonConst.LOGIN_TIME_10000);
            } else {
                SysRole sysRole = sysRoles.getFirst();
                menus = iSysMenuMapper.selectSysMenuByRoleId(sysRole.getRoleId());
            }
            List<SysMenuVO> sysMenuVOS = this.processMenus(menus);
            return Result.success(sysMenuVOS);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("异常", e);
            throw new ApiException(e.getMessage());
        }
    }
    
    private List<SysMenuVO> processMenus(List<SysMenu> menus) {
        List<SysMenuVO> sysMenuVOS = ISysMenuConvert.INSTANCE.convertList(menus);
        List<SysMenuVO> result = Lists.newArrayList();
        sysMenuVOS.forEach(sysMenuVO -> {
            if (sysMenuVO.getParentId() == 0) {
                this.getChildMenu(sysMenuVO, sysMenuVOS);
                result.add(sysMenuVO);
            }
        });
        return result.stream().sorted(Comparator.comparing(SysMenuVO::getOrderNum)).toList();
    }
    
    private void getChildMenu(SysMenuVO sysMenuVO, List<SysMenuVO> sysMenuVOS) {
        List<SysMenuVO> childrens = Lists.newArrayList();
        for (SysMenuVO list : sysMenuVOS) {
            if (list.getParentId().equals(sysMenuVO.getMenuId())) {
                childrens.add(list);
            }
        }
        if (childrens.isEmpty()) {
            return;
        } else {
            sysMenuVO.setChildMenu(childrens.stream().sorted(Comparator.comparing(SysMenuVO::getOrderNum)).toList());
            for (SysMenuVO list : childrens) {
                this.getChildMenu(list, childrens);
            }
        }
    }
    
    
}